package com.xndc.netty.iec104.codec;

import com.xndc.netty.iec104.model.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * IEC 104解码器
 */
@Slf4j
public class Iec104Decoder extends ByteToMessageDecoder {

    private static final byte START_CHAR = 0x68;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 1. 检查报文长度
        if (in.readableBytes() < 2) {
            return; // 需要更多数据
        }

        // 2. 标记当前读索引，以便回退
        in.markReaderIndex();

        // 3. 检查启动字符(0x68)
        byte startChar = in.readByte();
        if (startChar != START_CHAR) {
            in.resetReaderIndex();
            log.warn("收到无效的IEC 104帧，启动字符错误: 0x{}", String.format("%02X", startChar));
            return; // 不是有效的IEC 104帧
        }

        // 4. 读取长度字段
        byte length = in.readByte();

        // 5. 检查是否有足够的字节可读
        if (in.readableBytes() < length) {
            in.resetReaderIndex();
            return; // 需要更多数据
        }

        // 6. 提取完整的帧数据
        ByteBuf frameBuf = in.readBytes(length);
        byte[] frameBytes = new byte[length + 2]; // +2表示启动字符和长度字段
        frameBytes[0] = START_CHAR;
        frameBytes[1] = length;
        frameBuf.readBytes(frameBytes, 2, length);

        // 7. 根据控制域类型分类处理
        if (isControlFrame(frameBytes)) {
            // 处理控制帧(U/S帧)
            IEC104ControlFrame controlFrame = parseControlFrame(frameBytes);
            if (controlFrame != null) {
                out.add(controlFrame);
            }
        } else {
            // 处理信息帧(I帧)
            IEC104InformationFrame infoFrame = parseInformationFrame(frameBytes);
            if (infoFrame != null) {
                out.add(infoFrame);
            }
        }
    }

    /**
     * 判断是否为控制帧
     */
    private boolean isControlFrame(byte[] frameBytes) {
        // 获取控制域的第一个字节
        byte control1 = frameBytes[2];

        // I帧的第一位为0
        if ((control1 & 0x01) == 0) {
            return false;  // 是I帧
        }

        // S帧的前两位为10
        if ((control1 & 0x03) == 0x01) {
            return true;  // 是S帧
        }

        // U帧的前两位为11
        if ((control1 & 0x03) == 0x03) {
            return true;  // 是U帧
        }

        return false;  // 不应该到达这里
    }

    /**
     * 解析控制帧
     */
    private IEC104ControlFrame parseControlFrame(byte[] frameBytes) {
        IEC104ControlFrame frame = new IEC104ControlFrame();

        // 获取控制域
        byte control1 = frameBytes[2];
        byte control2 = frameBytes[3];
        byte control3 = frameBytes[4];
        byte control4 = frameBytes[5];

        // 判断是S帧还是U帧
        if ((control1 & 0x03) == 0x01) {
            // S帧: 确认帧
            frame.setControlType(IEC104ControlFrame.ControlType.S_FRAME);

            // 接收序列号(从control2和control3提取)
            short receiveSeq = (short) ((control3 << 8) | (control2 & 0xFE));
            receiveSeq = (short) (receiveSeq >> 1);
            frame.setReceiveSequence(receiveSeq);
        } else if ((control1 & 0x03) == 0x03) {
            // U帧: 根据控制功能位判断类型
            if ((control1 & 0x0C) == 0x04) {
                frame.setControlType(IEC104ControlFrame.ControlType.STARTDT_ACT);
            } else if ((control1 & 0x0C) == 0x08) {
                frame.setControlType(IEC104ControlFrame.ControlType.STARTDT_CON);
            } else if ((control1 & 0x10) == 0x10) {
                frame.setControlType(IEC104ControlFrame.ControlType.STOPDT_ACT);
            } else if ((control1 & 0x20) == 0x20) {
                frame.setControlType(IEC104ControlFrame.ControlType.STOPDT_CON);
            } else if ((control1 & 0x40) == 0x40) {
                frame.setControlType(IEC104ControlFrame.ControlType.TESTFR_ACT);
            } else if ((control1 & 0x80) == 0x80) {
                frame.setControlType(IEC104ControlFrame.ControlType.TESTFR_CON);
            }
        }

        return frame;
    }

    /**
     * 解析信息帧
     */
    private IEC104InformationFrame parseInformationFrame(byte[] frameBytes) {
        IEC104InformationFrame frame = new IEC104InformationFrame();

        // 获取控制域
        byte control1 = frameBytes[2];
        byte control2 = frameBytes[3];
        byte control3 = frameBytes[4];
        byte control4 = frameBytes[5];

        // 发送序列号(从control1和control2提取)
        short sendSeq = (short) ((control2 << 8) | control1);
        sendSeq = (short) (sendSeq >> 1);
        frame.setSendSequence(sendSeq);

        // 接收序列号(从control3和control4提取)
        short receiveSeq = (short) ((control4 << 8) | control3);
        receiveSeq = (short) (receiveSeq >> 1);
        frame.setReceiveSequence(receiveSeq);

        // ASDU解析
        if (frameBytes.length > 6) {
            ASDU asdu = parseASDU(frameBytes, 6);
            frame.setAsdu(asdu);
        }

        return frame;
    }

    /**
     * 解析ASDU
     */
    private ASDU parseASDU(byte[] frameBytes, int offset) {
        if (frameBytes.length < offset + 4) {
            // ASDU至少需要4个字节
            log.warn("ASDU长度不足: 需要至少4字节，实际只有{}字节", frameBytes.length - offset);
            return null;
        }

        ASDU asdu = new ASDU();

        // 解析类型标识
        byte typeId = frameBytes[offset];
        asdu.setTypeId(typeId);
        offset++;

        // 解析可变结构限定词(VSQ)
        byte vsq = frameBytes[offset];
        asdu.setVsq(vsq);
        // 从VSQ中提取信息对象数量和顺序标志位
        int objectCount = vsq & 0x7F; // 低7位表示对象数量
        boolean sq = (vsq & 0x80) == 0x80; // 最高位表示顺序标志
        offset++;

        // 解析传送原因(COT)
        byte cot = frameBytes[offset];
        asdu.setCot((byte) (cot & 0x3F));  // 低6位为传送原因
        asdu.setTest(((cot & 0x80) == 0x80));  // 测试位
        asdu.setNegative(((cot & 0x40) == 0x40));  // 否定确认位
        offset++;

        // 解析发起站地址（大多数情况下为0或不使用）
        if (offset + 1 < frameBytes.length) {
            byte originatorAddress = frameBytes[offset];
            asdu.setOriginatorAddress(originatorAddress);
            offset++;
        } else {
            asdu.setOriginatorAddress((short) 0);
        }

        // 解析公共地址(通常是2字节)
        if (offset + 1 < frameBytes.length) {
            short commonAddress = (short) (((frameBytes[offset + 1] & 0xFF) << 8) | (frameBytes[offset] & 0xFF));
            asdu.setCommonAddress(commonAddress);
            offset += 2;
        } else {
            // 如果只有一个字节（简化模式）
            asdu.setCommonAddress(frameBytes[offset]);
            offset++;
        }

        // 根据类型标识和顺序标志解析信息对象
        if (sq) {
            // 顺序信息对象 - 只有一个信息对象地址，多个连续值
            parseSequentialInformationObjects(asdu, frameBytes, offset, objectCount, typeId);
        } else {
            // 非顺序信息对象 - 每个信息对象都有自己的地址
            parseNonSequentialInformationObjects(asdu, frameBytes, offset, objectCount, typeId);
        }

        return asdu;
    }

    /**
     * 解析非顺序信息对象 (SQ=0)
     */
    private void parseNonSequentialInformationObjects(ASDU asdu, byte[] frameBytes, int offset, int objectCount, byte typeId) {
        int currentOffset = offset;

        for (int i = 0; i < objectCount; i++) {
            if (currentOffset + 3 > frameBytes.length) {
                log.warn("解析信息对象时数据不足: 类型={}, 对象序号={}", typeId, i);
                break;
            }

            // 创建新的信息对象
            InformationObject io = new InformationObject();

            // 解析信息对象地址(3字节)
            int ioa = ((frameBytes[currentOffset + 2] & 0xFF) << 16) |
                    ((frameBytes[currentOffset + 1] & 0xFF) << 8) |
                    (frameBytes[currentOffset] & 0xFF);
            io.setAddress(ioa);
            currentOffset += 3;

            // 根据类型标识解析信息元素
            currentOffset = parseInformationElement(io, frameBytes, currentOffset, typeId);

            // 添加到ASDU
            asdu.getInformationObjects().add(io);
        }
    }

    /**
     * 解析顺序信息对象 (SQ=1)
     */
    private void parseSequentialInformationObjects(ASDU asdu, byte[] frameBytes, int offset, int objectCount, byte typeId) {
        int currentOffset = offset;

        // 只解析一次信息对象地址
        if (currentOffset + 3 > frameBytes.length) {
            log.warn("解析顺序信息对象时数据不足");
            return;
        }

        // 解析基础信息对象地址
        int baseIoa = ((frameBytes[currentOffset + 2] & 0xFF) << 16) |
                ((frameBytes[currentOffset + 1] & 0xFF) << 8) |
                (frameBytes[currentOffset] & 0xFF);
        currentOffset += 3;

        // 为每个对象创建一个信息对象
        for (int i = 0; i < objectCount; i++) {
            InformationObject io = new InformationObject();
            io.setAddress(baseIoa + i); // 顺序地址

            // 解析信息元素
            currentOffset = parseInformationElement(io, frameBytes, currentOffset, typeId);

            // 添加到ASDU
            asdu.getInformationObjects().add(io);
        }
    }

    /**
     * 解析信息元素
     *
     * @return 新的偏移量
     */
    private int parseInformationElement(InformationObject io, byte[] frameBytes, int offset, byte typeId) {
        int currentOffset = offset;
        InformationElement element = new InformationElement();

        // 根据类型标识解析信息元素
        switch (typeId) {
            // ======== 监视方向过程信息 ========
            case 1:  // 单点信息 (M_SP_NA_1)
                if (currentOffset < frameBytes.length) {
                    boolean value = (frameBytes[currentOffset] & 0x01) == 0x01;
                    element.setValue(value);
                    
                    // 解析质量描述符
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFE) >> 1);
                    element.setQuality(quality);
                    
                    // 记录质量描述符详情
                    boolean blocked = (quality & 0x10) == 0x10;       // 封锁标志
                    boolean substituted = (quality & 0x20) == 0x20;   // 取代标志
                    boolean notTopical = (quality & 0x40) == 0x40;    // 不是当前值
                    boolean invalid = (quality & 0x80) == 0x80;       // 无效标志
                    
                    // 将质量描述符详情记录到日志或用于其他处理
                    if (blocked || substituted || notTopical || invalid) {
                        log.debug("单点信息质量描述符: 封锁={}, 取代={}, 非当前值={}, 无效={}",
                                blocked, substituted, notTopical, invalid);
                    }
                    
                    currentOffset++;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 2:  // 带时标的单点信息 (M_SP_TA_1)
                if (currentOffset < frameBytes.length) {
                    boolean value = (frameBytes[currentOffset] & 0x01) == 0x01;
                    element.setValue(value);
                    
                    // 解析质量描述符
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFE) >> 1);
                    element.setQuality(quality);
                    currentOffset++;
                    
                    // 解析24位时标（CP24Time2a）
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;

            case 3:  // 双点信息 (M_DP_NA_1)
                if (currentOffset < frameBytes.length) {
                    // 双点值在第1-2位
                    int value = frameBytes[currentOffset] & 0x03;
                    element.setValue(value);
                    
                    // 双点信息值的含义
                    String stateDesc;
                    switch (value) {
                        case 0: stateDesc = "中间状态"; break;
                        case 1: stateDesc = "确定开"; break;
                        case 2: stateDesc = "确定关"; break;
                        case 3: stateDesc = "不确定"; break;
                        default: stateDesc = "未知状态";
                    }
                    log.debug("双点信息: 值={} ({})", value, stateDesc);
                    
                    // 解析质量描述符
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFC) >> 2);
                    element.setQuality(quality);
                    currentOffset++;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 4:  // 带时标的双点信息 (M_DP_TA_1)
                if (currentOffset < frameBytes.length) {
                    int value = frameBytes[currentOffset] & 0x03;
                    element.setValue(value);
                    
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFC) >> 2);
                    element.setQuality(quality);
                    currentOffset++;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;

            case 5:  // 步位置信息 (M_ST_NA_1)
                if (currentOffset + 1 < frameBytes.length) {
                    // 步位置值（带符号的7位数)
                    byte value = (byte)(frameBytes[currentOffset] & 0x7F);
                    // 判断第7位是否为1，如果是则为负值
                    if ((frameBytes[currentOffset] & 0x40) == 0x40) {
                        value = (byte)(value | 0x80); // 扩展符号位
                    }
                    element.setValue(value);
                    
                    // 瞬变状态（用于指示值是否在变化中）
                    boolean isTransient = (frameBytes[currentOffset] & 0x80) == 0x80;
                    log.debug("步位置信息: 值={}, 瞬变={}", value, isTransient);

                    // 质量描述符
                    byte quality = frameBytes[currentOffset + 1];
                    element.setQuality(quality);
                    currentOffset += 2;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 6:  // 带时标的步位置信息 (M_ST_TA_1)
                if (currentOffset + 1 < frameBytes.length) {
                    byte value = (byte)(frameBytes[currentOffset] & 0x7F);
                    if ((frameBytes[currentOffset] & 0x40) == 0x40) {
                        value = (byte)(value | 0x80);
                    }
                    element.setValue(value);
                    
                    boolean isTransient = (frameBytes[currentOffset] & 0x80) == 0x80;
                    
                    byte quality = frameBytes[currentOffset + 1];
                    element.setQuality(quality);
                    currentOffset += 2;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;
                
            case 7:  // 32位比特串 (M_BO_NA_1)
                if (currentOffset + 4 < frameBytes.length) {
                    // 32位比特串
                    int bitString = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                                   ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                   ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                   (frameBytes[currentOffset] & 0xFF);
                    element.setValue(bitString);
                    
                    // 质量描述符
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    currentOffset += 5;
                    
                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 8:  // 带时标的32位比特串 (M_BO_TA_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int bitString = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                                   ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                   ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                   (frameBytes[currentOffset] & 0xFF);
                    element.setValue(bitString);
                    
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    currentOffset += 5;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;

            case 9:  // 归一化测量值 (M_ME_NA_1)
                if (currentOffset + 2 < frameBytes.length) {
                    // 归一化值是16位有符号整数，范围在-1到+1之间
                    short rawValue = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                          (frameBytes[currentOffset] & 0xFF));
                    element.setValue(rawValue);
                    
                    // 可以在这里计算规一化的实际值
                    float normalizedValue = rawValue / 32767.0f;
                    log.debug("归一化测量值: 原始值={}, 归一化值={}", rawValue, normalizedValue);

                    // 质量描述符
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    
                    // 解析质量描述符
                    boolean overflow = (quality & 0x01) == 0x01;      // 溢出标志
                    boolean blocked = (quality & 0x10) == 0x10;       // 封锁标志
                    boolean substituted = (quality & 0x20) == 0x20;   // 取代标志
                    boolean notTopical = (quality & 0x40) == 0x40;    // 不是当前值
                    boolean invalid = (quality & 0x80) == 0x80;       // 无效标志
                    
                    currentOffset += 3;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 10:  // 带时标的归一化测量值 (M_ME_TA_1)
                if (currentOffset + 2 < frameBytes.length) {
                    short rawValue = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                          (frameBytes[currentOffset] & 0xFF));
                    element.setValue(rawValue);
                    
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    currentOffset += 3;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;

            case 11:  // 标度化测量值 (M_ME_NB_1)
                if (currentOffset + 2 < frameBytes.length) {
                    // 标度化值是16位有符号整数
                    short value = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                       (frameBytes[currentOffset] & 0xFF));
                    element.setValue(value);
                    
                    // 标度化值通常需要与配置中的定标因子结合使用
                    log.debug("标度化测量值: {}", value);

                    // 质量描述符
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    
                    // 解析质量描述符（与归一化测量值相同）
                    boolean overflow = (quality & 0x01) == 0x01;
                    boolean blocked = (quality & 0x10) == 0x10;
                    boolean substituted = (quality & 0x20) == 0x20;
                    boolean notTopical = (quality & 0x40) == 0x40;
                    boolean invalid = (quality & 0x80) == 0x80;
                    
                    currentOffset += 3;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 12:  // 带时标的标度化测量值 (M_ME_TB_1)
                if (currentOffset + 2 < frameBytes.length) {
                    short value = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                       (frameBytes[currentOffset] & 0xFF));
                    element.setValue(value);
                    
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    currentOffset += 3;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;

            case 13:  // 短浮点数 (M_ME_NC_1)
                if (currentOffset + 4 < frameBytes.length) {
                    // IEEE 754浮点数
                    int bits = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                              ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                              ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                              (frameBytes[currentOffset] & 0xFF);
                    float value = Float.intBitsToFloat(bits);
                    element.setValue(value);
                    
                    log.debug("短浮点测量值: {}", value);

                    // 质量描述符
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    
                    // 解析质量描述符（与归一化测量值相同）
                    boolean overflow = (quality & 0x01) == 0x01;
                    boolean blocked = (quality & 0x10) == 0x10;
                    boolean substituted = (quality & 0x20) == 0x20;
                    boolean notTopical = (quality & 0x40) == 0x40;
                    boolean invalid = (quality & 0x80) == 0x80;
                    
                    currentOffset += 5;

                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 14:  // 带时标的短浮点数 (M_ME_TC_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int bits = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                              ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                              ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                              (frameBytes[currentOffset] & 0xFF);
                    float value = Float.intBitsToFloat(bits);
                    element.setValue(value);
                    
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    currentOffset += 5;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;
                
            case 15:  // 累积量 (M_IT_NA_1)
                if (currentOffset + 4 < frameBytes.length) {
                    // 二进制计数器读数(BCR)
                    int counterValue = ((frameBytes[currentOffset+3] & 0x3F) << 24) |
                                      ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                      ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                      (frameBytes[currentOffset] & 0xFF);
                    element.setValue(counterValue);
                    
                    // 序列号SQ (bit 6-7 of byte 4)
                    int sq = (frameBytes[currentOffset+3] & 0xC0) >> 6;
                    
                    // 解析BCR状态
                    boolean invalid = (frameBytes[currentOffset+4] & 0x80) == 0x80;    // IV - 无效
                    boolean counted = (frameBytes[currentOffset+4] & 0x40) == 0x40;    // CA - 计数器被调整
                    boolean adjusted = (frameBytes[currentOffset+4] & 0x20) == 0x20;   // CY - 计数器溢出
                    boolean overflow = (frameBytes[currentOffset+4] & 0x10) == 0x10;   // OV - 由于溢出而带有进位
                    
                    log.debug("累积量: 值={}, SQ={}, 无效={}, 计数={}, 调整={}, 溢出={}",
                             counterValue, sq, invalid, counted, adjusted, overflow);
                    
                    currentOffset += 5;
                    
                    // 检查是否有时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 16:  // 带时标的累积量 (M_IT_TA_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int counterValue = ((frameBytes[currentOffset+3] & 0x3F) << 24) |
                                      ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                      ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                      (frameBytes[currentOffset] & 0xFF);
                    element.setValue(counterValue);
                    
                    byte status = frameBytes[currentOffset + 4];
                    currentOffset += 5;
                    
                    // 解析24位时标
                    if (currentOffset + 2 < frameBytes.length) {
                        byte[] timestamp = new byte[3];
                        System.arraycopy(frameBytes, currentOffset, timestamp, 0, 3);
                        element.setTimestamp(timestamp);
                        currentOffset += 3;
                    }
                }
                break;
                
            case 30:  // 带时标CP56Time2a的单点信息 (M_SP_TB_1)
                if (currentOffset < frameBytes.length) {
                    boolean value = (frameBytes[currentOffset] & 0x01) == 0x01;
                    element.setValue(value);
                    
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFE) >> 1);
                    element.setQuality(quality);
                    currentOffset++;
                    
                    // 解析CP56Time2a时标（7字节）
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 31:  // 带时标CP56Time2a的双点信息 (M_DP_TB_1)
                if (currentOffset < frameBytes.length) {
                    int value = frameBytes[currentOffset] & 0x03;
                    element.setValue(value);
                    
                    byte quality = (byte)((frameBytes[currentOffset] & 0xFC) >> 2);
                    element.setQuality(quality);
                    currentOffset++;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            case 32:  // 带时标CP56Time2a的步位置信息 (M_ST_TB_1)
                if (currentOffset + 1 < frameBytes.length) {
                    byte value = (byte)(frameBytes[currentOffset] & 0x7F);
                    if ((frameBytes[currentOffset] & 0x40) == 0x40) {
                        value = (byte)(value | 0x80);
                    }
                    element.setValue(value);
                    
                    boolean isTransient = (frameBytes[currentOffset] & 0x80) == 0x80;
                    
                    byte quality = frameBytes[currentOffset + 1];
                    element.setQuality(quality);
                    currentOffset += 2;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;

            case 33:  // 带时标CP56Time2a的32位比特串 (M_BO_TB_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int bitString = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                                   ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                   ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                   (frameBytes[currentOffset] & 0xFF);
                    element.setValue(bitString);
                    
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    currentOffset += 5;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;

            case 34:  // 带时标CP56Time2a的归一化测量值 (M_ME_TD_1)
                if (currentOffset + 2 < frameBytes.length) {
                    short value = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                       (frameBytes[currentOffset] & 0xFF));
                    element.setValue(value);
                    
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    currentOffset += 3;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;

            case 35:  // 带时标CP56Time2a的标度化测量值 (M_ME_TE_1)
                if (currentOffset + 2 < frameBytes.length) {
                    short value = (short)(((frameBytes[currentOffset+1] & 0xFF) << 8) | 
                                       (frameBytes[currentOffset] & 0xFF));
                    element.setValue(value);
                    
                    byte quality = frameBytes[currentOffset + 2];
                    element.setQuality(quality);
                    currentOffset += 3;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;

            case 36:  // 带时标CP56Time2a的短浮点数 (M_ME_TF_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int bits = ((frameBytes[currentOffset+3] & 0xFF) << 24) |
                              ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                              ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                              (frameBytes[currentOffset] & 0xFF);
                    float value = Float.intBitsToFloat(bits);
                    element.setValue(value);
                    
                    byte quality = frameBytes[currentOffset + 4];
                    element.setQuality(quality);
                    currentOffset += 5;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;

            case 37:  // 带时标CP56Time2a的累积量 (M_IT_TB_1)
                if (currentOffset + 4 < frameBytes.length) {
                    int counterValue = ((frameBytes[currentOffset+3] & 0x3F) << 24) |
                                      ((frameBytes[currentOffset+2] & 0xFF) << 16) |
                                      ((frameBytes[currentOffset+1] & 0xFF) << 8) |
                                      (frameBytes[currentOffset] & 0xFF);
                    element.setValue(counterValue);
                    
                    byte status = frameBytes[currentOffset + 4];
                    currentOffset += 5;
                    
                    // 解析CP56Time2a时标
                    currentOffset = parseTimestamp(element, frameBytes, currentOffset);
                }
                break;
                
            // 其他监视方向类型可以继续添加...
                
            // ======== 控制方向过程信息 ========
            case 45:  // 单点命令
                if (currentOffset < frameBytes.length) {
                    // 单点命令在第1位
                    boolean value = (frameBytes[currentOffset] & 0x01) == 0x01;
                    element.setValue(value);

                    // 选择/执行标志在第8位，其他位为保留位
                    boolean isSelect = (frameBytes[currentOffset] & 0x80) == 0x80;
                    // 这里可以存储选择/执行标志，但我们当前的InformationElement没有这个字段
                    currentOffset++;
                }
                break;

            case 46:  // 双点命令
                if (currentOffset < frameBytes.length) {
                    // 双点命令在第1-2位
                    int value = frameBytes[currentOffset] & 0x03;
                    element.setValue(value);

                    // 选择/执行标志在第8位
                    boolean isSelect = (frameBytes[currentOffset] & 0x80) == 0x80;
                    currentOffset++;
                }
                break;

            case 48:  // 步调节命令
                if (currentOffset < frameBytes.length) {
                    // 步调节值在第1-7位
                    byte value = (byte) (frameBytes[currentOffset] & 0x7F);
                    // 判断第7位是否为1，如果是则为负值
                    if ((frameBytes[currentOffset] & 0x40) == 0x40) {
                        value = (byte) (value | 0x80); // 扩展符号位
                    }
                    element.setValue(value);

                    // 选择/执行标志在第8位
                    boolean isSelect = (frameBytes[currentOffset] & 0x80) == 0x80;
                    currentOffset++;
                }
                break;

            case 50:  // 设点命令，归一化值
            case 51:  // 设点命令，标度化值
                if (currentOffset + 2 < frameBytes.length) {
                    // 设点值是16位有符号整数
                    short value = (short) (((frameBytes[currentOffset + 1] & 0xFF) << 8) |
                            (frameBytes[currentOffset] & 0xFF));
                    element.setValue(value);

                    // 选择/执行标志在第8位
                    boolean isSelect = (frameBytes[currentOffset + 2] & 0x80) == 0x80;
                    currentOffset += 3;
                }
                break;

            case 58:  // 设点命令，短浮点数
                if (currentOffset + 4 < frameBytes.length) {
                    // IEEE 754浮点数
                    int bits = ((frameBytes[currentOffset + 3] & 0xFF) << 24) |
                            ((frameBytes[currentOffset + 2] & 0xFF) << 16) |
                            ((frameBytes[currentOffset + 1] & 0xFF) << 8) |
                            (frameBytes[currentOffset] & 0xFF);
                    float value = Float.intBitsToFloat(bits);
                    element.setValue(value);

                    // 选择/执行标志在下一个字节的第8位
                    boolean isSelect = (frameBytes[currentOffset + 4] & 0x80) == 0x80;
                    currentOffset += 5;
                }
                break;

            // ======== 系统信息 ========
            case 70:  // 初始化结束
                if (currentOffset < frameBytes.length) {
                    // 初始化原因
                    byte cause = frameBytes[currentOffset];
                    element.setValue(cause);
                    currentOffset++;
                }
                break;

            case 100:  // 总召唤命令
                if (currentOffset < frameBytes.length) {
                    // 召唤限定词
                    byte qualifier = frameBytes[currentOffset];
                    element.setValue(qualifier);
                    currentOffset++;
                }
                break;

            case 103:  // 时钟同步命令
                if (currentOffset + 6 < frameBytes.length) {
                    // 7字节时标
                    byte[] timestamp = new byte[7];
                    System.arraycopy(frameBytes, currentOffset, timestamp, 0, 7);
                    element.setTimestamp(timestamp);
                    element.setValue(decodeCP56Time2a(timestamp));
                    currentOffset += 7;
                }
                break;

            default:
                // 默认只获取一个字节作为值
                if (currentOffset < frameBytes.length) {
                    element.setValue(frameBytes[currentOffset]);
                    currentOffset++;
                }
                log.warn("不支持的类型标识: {}", typeId);
        }

        // 添加信息元素到信息对象
        io.getElements().add(element);

        return currentOffset;
    }

    /**
     * 解析时标（如果存在）
     *
     * @return 新的偏移量
     */
    private int parseTimestamp(InformationElement element, byte[] frameBytes, int offset) {
        int currentOffset = offset;

        // 检查是否还有足够的字节来解析时标
        if (currentOffset + 6 < frameBytes.length) {
            // CP56Time2a格式的时标（7字节）
            byte[] timestamp = new byte[7];
            System.arraycopy(frameBytes, currentOffset, timestamp, 0, 7);
            element.setTimestamp(timestamp);
            currentOffset += 7;
        }

        return currentOffset;
    }

    /**
     * 解码CP56Time2a格式的时标
     */
    private long decodeCP56Time2a(byte[] timestamp) {
        if (timestamp.length < 7) {
            return 0;
        }

        int milliseconds = (timestamp[0] & 0xFF) | ((timestamp[1] & 0x01) << 8);
        int minutes = (timestamp[2] & 0x3F);
        int hours = (timestamp[3] & 0x1F);
        int dayOfMonth = (timestamp[4] & 0x1F);
        int month = ((timestamp[5] & 0x0F) - 1); // 月份从0开始
        int year = (timestamp[6] & 0x7F) + 2000; // 相对于2000年

        // 这里应该构造一个完整的时间对象，但为了简化，我们返回毫秒时间戳
        // 在实际应用中，应该使用Calendar或LocalDateTime进行正确处理
        return milliseconds;
    }
} 